home *** CD-ROM | disk | FTP | other *** search
/ Giga Games 1 / Giga Games.iso / net / hack / 3_1_3 / win / x11 / winmap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-24  |  28.9 KB  |  1,066 lines

  1. /*    SCCS Id: @(#)winmap.c    3.1    93/02/02          */
  2. /* Copyright (c) Dean Luick, 1992                  */
  3. /* NetHack may be freely redistributed.  See license for details. */
  4.  
  5. /*
  6.  * This file contains:
  7.  *    + global functions print_glyph() and cliparound()
  8.  *     + the map window routines
  9.  *    + the char and pointer input routines
  10.  *
  11.  * Notes:
  12.  *    + We don't really have a good way to get the compiled ROWNO and 
  13.  *      COLNO as defaults.  They are hardwired to the current "correct"
  14.  *      values in the Window widget.  I am _not_ in favor of including
  15.  *      some nethack include file for Window.c.
  16.  */
  17.  
  18. #ifndef SYSV
  19. #define PRESERVE_NO_SYSV    /* X11 include files may define SYSV */
  20. #endif
  21.  
  22. #include <X11/Intrinsic.h>
  23. #include <X11/StringDefs.h>
  24. #include <X11/Shell.h>
  25. #include <X11/Xaw/Cardinals.h>
  26. #include <X11/Xaw/Scrollbar.h>
  27. #include <X11/Xaw/Viewport.h>
  28. #include <X11/Xatom.h>
  29.  
  30. #ifdef PRESERVE_NO_SYSV
  31. # ifdef SYSV
  32. #  undef SYSV
  33. # endif
  34. # undef PRESERVE_NO_SYSV
  35. #endif
  36.  
  37. #include "Window.h"    /* map widget declarations */
  38.  
  39. #include "hack.h"
  40. #include "winX.h"
  41.  
  42. /* Define these if you really want a lot of junk on your screen. */
  43. /* #define VERBOSE        /* print various info & events as they happen */
  44. /* #define VERBOSE_UPDATE    /* print screen update bounds */
  45. /* #define VERBOSE_INPUT    /* print input events */
  46.  
  47. static void FDECL(set_button_values, (Widget,int,int,unsigned));
  48. static void FDECL(map_check_size_change, (struct xwindow *));
  49. static void FDECL(map_update, (struct xwindow *,int,int,int,int,BOOLEAN_P));
  50. static void FDECL(map_exposed, (Widget,XtPointer,XtPointer));
  51. static void FDECL(set_gc, (Widget,Font,char *,Pixel,GC *,GC *));
  52. static void FDECL(get_gc, (struct xwindow *,Font));
  53. static void FDECL(get_char_info, (struct xwindow *));
  54. static void FDECL(display_cursor, (struct xwindow *));
  55.  
  56. /* Global functions ======================================================== */
  57.  
  58. void
  59. X11_print_glyph(window, x, y, glyph)
  60.     winid window;
  61.     xchar x, y;
  62.     int glyph;
  63. {
  64.     uchar          ch;
  65.     register int      offset;
  66.     struct map_info_t *map_info;
  67.     register unsigned char *ch_ptr;
  68. #ifdef TEXTCOLOR
  69.     int     color;
  70.     register unsigned char *co_ptr;
  71.  
  72. #define zap_color(n)  color = zapcolors[n]
  73. #define cmap_color(n) color = defsyms[n].color
  74. #define trap_color(n) color = (n == WEB) ? defsyms[S_web ].color : \
  75.                        defsyms[S_trap].color
  76. #define obj_color(n)  color = objects[n].oc_color
  77. #define mon_color(n)  color = mons[n].mcolor
  78. #define pet_color(n)  color = mons[n].mcolor
  79.  
  80. # else /* no text color */
  81.  
  82. #define zap_color(n)
  83. #define cmap_color(n)
  84. #define trap_color(n)
  85. #define obj_color(n)
  86. #define mon_color(n)
  87. #define pet_color(n)
  88. #endif
  89.  
  90.     check_winid(window);
  91.     if (window_list[window].type != NHW_MAP) {
  92.     impossible("print_glyph: can (currently) only print to map windows");
  93.     return;
  94.     }
  95.     map_info = window_list[window].map_information;
  96.  
  97.     /*
  98.      *  Map the glyph back to a character.
  99.      *
  100.      *  Warning:  For speed, this makes an assumption on the order of
  101.      *            offsets.  The order is set in display.h.
  102.      */
  103.     if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) {        /* swallow */
  104.     /* see swallow_to_glyph() in display.c */
  105.     ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)];
  106.     mon_color(offset >> 3);
  107.     } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) {    /* zap beam */
  108.     /* see zapdir_to_glyph() in display.c */
  109.     ch = showsyms[S_vbeam + (offset & 0x3)];
  110.     zap_color((offset >> 2));
  111.     } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) {    /* cmap */
  112.     ch = showsyms[offset];
  113.     cmap_color(offset);
  114.     } else if ((offset = (glyph - GLYPH_TRAP_OFF)) >= 0) {    /* trap */
  115.     ch = (offset == WEB) ? showsyms[S_web] : showsyms[S_trap];
  116.     trap_color(offset);
  117.     } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) {    /* object */
  118.     ch = oc_syms[objects[offset].oc_class];
  119.     obj_color(offset);
  120.     } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) {    /* a corpse */
  121.     ch = oc_syms[objects[CORPSE].oc_class];
  122.     mon_color(offset);
  123.     } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) {    /* a pet */
  124.     ch = monsyms[mons[offset].mlet];
  125.     pet_color(offset);
  126.     } else {                            /* a monster */
  127.     ch = monsyms[mons[glyph].mlet];
  128.     mon_color(glyph);
  129.     }
  130.  
  131.     /* Only update if we need to. */
  132.     ch_ptr = &map_info->text[y][x];
  133.  
  134. #ifdef TEXTCOLOR
  135.     co_ptr = &map_info->colors[y][x];
  136.     if (*ch_ptr != ch || *co_ptr != color)
  137. #else
  138.     if (*ch_ptr != ch)
  139. #endif
  140.     {
  141.     *ch_ptr = ch;
  142. #ifdef TEXTCOLOR
  143.     *co_ptr = color;
  144. #endif
  145.     /* update row bbox */
  146.     if ((uchar) x < map_info->t_start[y]) map_info->t_start[y] = x;
  147.     if ((uchar) x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
  148.     }
  149.  
  150. #undef zap_color
  151. #undef cmap_color
  152. #undef trap_color
  153. #undef obj_color
  154. #undef mon_color
  155. #undef pet_color
  156. }
  157.  
  158. #ifdef CLIPPING
  159. /*
  160.  * The is the tty clip call.  Since X can resize at any time, we can't depend
  161.  * on this being defined.
  162.  */
  163. /*ARGSUSED*/
  164. void X11_cliparound(x, y) int x, y; { }
  165. #endif /* CLIPPING */
  166.  
  167. /* End global functions ==================================================== */
  168.  
  169.  
  170. /*
  171.  * Make sure the map's cursor is always visible.
  172.  */
  173. void
  174. check_cursor_visibility(wp)
  175.     struct xwindow *wp;
  176. {
  177.     Arg arg[2];
  178.     Widget viewport, horiz_sb, vert_sb;
  179.     float top, shown, cursor_middle;
  180.     Boolean do_call, adjusted = False;
  181. #ifdef VERBOSE
  182.     char *s;
  183. #endif
  184.  
  185.     viewport = XtParent(wp->w);
  186.     horiz_sb = XtNameToWidget(viewport, "horizontal");
  187.     vert_sb  = XtNameToWidget(viewport, "vertical");
  188.  
  189. #define V_BORDER 0.1        /* if this far from vert edge, shift */
  190. #define H_BORDER 0.0625        /* if this from from horiz edge, shift */
  191.  
  192. #define H_DELTA 0.25        /* distance of horiz shift */
  193.                 /* vert shift is half of curr distance */
  194. /* The V_DELTA is 1/2 the value of shown. */
  195.  
  196.     if (horiz_sb) {
  197.     XtSetArg(arg[0], XtNshown,    &shown);
  198.     XtSetArg(arg[1], XtNtopOfThumb, &top);
  199.     XtGetValues(horiz_sb, arg, TWO);
  200.  
  201.     cursor_middle = (((float) wp->cursx) + 0.5) / (float) COLNO;
  202.     do_call = True;
  203.  
  204. #ifdef VERBOSE
  205.     if (cursor_middle < top) {
  206.         s = " outside left";
  207.     } else if (cursor_middle < top + H_BORDER) {
  208.         s = " close to left";
  209.     } else if (cursor_middle > (top + shown)) {
  210.         s = " outside right";
  211.     } else if (cursor_middle > (top + shown - H_BORDER)) {
  212.         s = " close to right";
  213.     } else {
  214.         s = "";
  215.     }
  216.     printf("Horiz: shown = %3.2f, top = %3.2f%s", shown, top, s);
  217. #endif
  218.  
  219.     if (cursor_middle < top) {
  220.         top = cursor_middle - H_DELTA;
  221.         if (top < 0.0) top = 0;
  222.     } else if (cursor_middle < top + H_BORDER) {
  223.         top -= H_DELTA;
  224.         if (top < 0.0) top = 0.0;
  225.     } else if (cursor_middle > (top + shown)) {
  226.         top = cursor_middle + H_DELTA;
  227.         if (top + shown > 1.0) top = 1.0 - shown;
  228.     } else if (cursor_middle > (top + shown - H_BORDER)) {
  229.         top += H_DELTA;
  230.         if (top + shown > 1.0) top = 1.0 - shown;
  231.     } else {
  232.         do_call = False;
  233.     }
  234.  
  235.     if (do_call) {
  236.         XtCallCallbacks(horiz_sb, XtNjumpProc, &top);
  237.         adjusted = True;
  238.     }
  239.     }
  240.  
  241.     if (vert_sb) {
  242.     XtSetArg(arg[0], XtNshown,      &shown);
  243.     XtSetArg(arg[1], XtNtopOfThumb, &top);
  244.     XtGetValues(vert_sb, arg, TWO);
  245.  
  246.     cursor_middle = (((float) wp->cursy) + 0.5) / (float) ROWNO;
  247.     do_call = True;
  248.  
  249. #ifdef VERBOSE
  250.     if (cursor_middle < top) {
  251.         s = " above top";
  252.     } else if (cursor_middle < top + V_BORDER) {
  253.         s = " close to top";
  254.     } else if (cursor_middle > (top + shown)) {
  255.         s = " below bottom";
  256.     } else if (cursor_middle > (top + shown - V_BORDER)) {
  257.         s = " close to bottom";
  258.     } else {
  259.         s = "";
  260.     }
  261.     printf("%sVert: shown = %3.2f, top = %3.2f%s",
  262.                     horiz_sb ? ";  " : "", shown, top, s);
  263. #endif
  264.  
  265.     if (cursor_middle < top) {
  266.         top = cursor_middle - (shown / 2.0);
  267.         if (top < 0.0) top = 0;
  268.     } else if (cursor_middle < top + V_BORDER) {
  269.         top -= shown / 2.0;
  270.         if (top < 0.0) top = 0;
  271.     } else if (cursor_middle > (top + shown)) {
  272.         top = cursor_middle - (shown / 2.0);
  273.         if (top < 0.0) top = 0;
  274.         if (top + shown > 1.0) top = 1.0 - shown;
  275.     } else if (cursor_middle > (top + shown - V_BORDER)) {
  276.         top += shown / 2.0;
  277.         if (top + shown > 1.0) top = 1.0 - shown;
  278.     } else {
  279.         do_call = False;
  280.     }
  281.  
  282.     if (do_call) {
  283.         XtCallCallbacks(vert_sb, XtNjumpProc, &top);
  284.         adjusted = True;
  285.     }
  286.     }
  287.  
  288.     /* make sure cursor is displayed during dowhatis.. */
  289.     if (adjusted) display_cursor(wp);
  290.  
  291. #ifdef VERBOSE
  292.     if (horiz_sb || vert_sb) printf("\n");
  293. #endif
  294. }
  295.  
  296.  
  297. /*
  298.  * Check to see if the viewport has grown smaller.  If so, then we want to make
  299.  * sure that the cursor is still on the screen.  We do this to keep the cursor
  300.  * on the screen when the user resizes the nethack window.
  301.  */
  302. static void
  303. map_check_size_change(wp)
  304.     struct xwindow *wp;
  305. {
  306.     struct map_info_t *map_info = wp->map_information;
  307.     Arg arg[2];
  308.     Dimension new_width, new_height;
  309.     Widget viewport;
  310.  
  311.     viewport = XtParent(wp->w);
  312.  
  313.     XtSetArg(arg[0], XtNwidth,  &new_width);
  314.     XtSetArg(arg[1], XtNheight, &new_height);
  315.     XtGetValues(viewport, arg, TWO);
  316.  
  317.     /* Only do cursor check if new size is smaller. */
  318.     if (new_width < map_info->viewport_width
  319.             || new_height < map_info->viewport_height) {
  320.     check_cursor_visibility(wp);
  321.     }
  322.  
  323.     map_info->viewport_width = new_width;
  324.     map_info->viewport_height = new_height;
  325. }
  326.  
  327. /*
  328.  * Fill in parameters "regular" and "inverse" with newly created GCs.
  329.  * Using the given background pixel and the foreground pixel optained
  330.  * by querying the widget with the resource name.
  331.  */
  332. static void
  333. set_gc(w, font, resource_name, bgpixel, regular, inverse)
  334.     Widget w;
  335.     Font font;
  336.     char *resource_name;
  337.     Pixel bgpixel;
  338.     GC   *regular, *inverse;
  339. {
  340.     XGCValues values;
  341.     XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont;
  342.     Pixel curpixel;
  343.     Arg arg[1];
  344.  
  345.     XtSetArg(arg[0], resource_name, &curpixel);
  346.     XtGetValues(w, arg, ONE);
  347.  
  348.     values.foreground = curpixel;
  349.     values.background = bgpixel;
  350.     values.function   = GXcopy;
  351.     values.font          = font;
  352.     *regular = XtGetGC(w, mask, &values);
  353.     values.foreground = bgpixel;
  354.     values.background = curpixel;
  355.     values.function   = GXcopy;
  356.     values.font          = font;
  357.     *inverse = XtGetGC(w, mask, &values);
  358. }
  359.  
  360. /*
  361.  * Create the GC's for each color.
  362.  *
  363.  * I'm not sure if it is a good idea to have a GC for each color (and
  364.  * inverse). It might be faster to just modify the foreground and
  365.  * background colors on the current GC as needed.
  366.  */
  367. static void
  368. get_gc(wp, font)
  369.     struct xwindow *wp;
  370.     Font font;
  371. {
  372.     struct map_info_t *map_info = wp->map_information;
  373.     Pixel bgpixel;
  374.     Arg arg[1];
  375.  
  376.     /* Get background pixel. */
  377.     XtSetArg(arg[0], XtNbackground, &bgpixel);
  378.     XtGetValues(wp->w, arg, ONE);
  379.  
  380. #ifdef TEXTCOLOR
  381. #define set_color_gc(nh_color, resource_name)            \
  382.         set_gc(wp->w, font, resource_name, bgpixel,        \
  383.             &map_info->color_gcs[nh_color],        \
  384.             &map_info->inv_color_gcs[nh_color]);
  385.  
  386.     set_color_gc(BLACK,         XtNblack);
  387.     set_color_gc(RED,         XtNred);
  388.     set_color_gc(GREEN,         XtNgreen);
  389.     set_color_gc(BROWN,         XtNbrown);
  390.     set_color_gc(BLUE,         XtNblue);
  391.     set_color_gc(MAGENTA,     XtNmagenta);
  392.     set_color_gc(CYAN,         XtNcyan);
  393.     set_color_gc(GRAY,         XtNgray);
  394.     set_color_gc(NO_COLOR,     XtNforeground);
  395.     set_color_gc(ORANGE_COLORED, XtNorange);
  396.     set_color_gc(BRIGHT_GREEN,     XtNbright_green);
  397.     set_color_gc(YELLOW,     XtNyellow);
  398.     set_color_gc(BRIGHT_BLUE,     XtNbright_blue);
  399.     set_color_gc(BRIGHT_MAGENTA, XtNbright_magenta);
  400.     set_color_gc(BRIGHT_CYAN,     XtNbright_cyan);
  401.     set_color_gc(WHITE,         XtNwhite);
  402. #else
  403.     set_gc(wp->w, font, XtNforeground, bgpixel,
  404.                 &map_info->copy_gc, &map_info->inv_copy_gc);
  405. #endif
  406. }
  407.  
  408.  
  409. /*
  410.  * Display the cursor on the map window.
  411.  */
  412. static void
  413. display_cursor(wp)
  414.     struct xwindow *wp;
  415. {
  416.     /* Redisplay the cursor location inverted. */
  417.     map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE);
  418. }
  419.  
  420.  
  421. /*
  422.  * Check if there are any changed characters.  If so, then plaster them on
  423.  * the screen.
  424.  */
  425. void
  426. display_map_window(wp)
  427.     struct xwindow *wp;
  428. {
  429.     register int row;
  430.     struct map_info_t *map_info = wp->map_information;
  431.  
  432.     /*
  433.      * If the previous cursor position is not the same as the current
  434.      * cursor position, then update the old cursor position.
  435.      */
  436.     if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) {
  437.     register unsigned int x = wp->prevx, y = wp->prevy;
  438.     if (x < map_info->t_start[y]) map_info->t_start[y] = x;
  439.     if (x > map_info->t_stop[y])  map_info->t_stop[y]  = x;
  440.     }
  441.  
  442.     for (row = 0; row < ROWNO; row++) {
  443.     if (map_info->t_start[row] <= map_info->t_stop[row]) {
  444.         map_update(wp, row, row,
  445.             (int) map_info->t_start[row],
  446.             (int) map_info->t_stop[row], FALSE);
  447.         map_info->t_start[row] = COLNO-1;
  448.         map_info->t_stop[row] = 0;
  449.     }
  450.     }
  451.     display_cursor(wp);
  452.     wp->prevx = wp->cursx;    /* adjust old cursor position */
  453.     wp->prevy = wp->cursy;
  454. }
  455.  
  456. /*
  457.  * Fill the saved screen characters with the "clear" character, and reset
  458.  * all colors to the neutral color.  Flush out everything by resetting the
  459.  * "new" bounds and calling display_map_window().
  460.  */
  461. void
  462. clear_map_window(wp)
  463.     struct xwindow *wp;
  464. {
  465.     struct map_info_t *map_info = wp->map_information;
  466.  
  467.     /* Fill with spaces, and update */
  468.     (void) memset((genericptr_t) map_info->text, ' ',
  469.             sizeof(map_info->text));
  470.     (void) memset((genericptr_t) map_info->t_start, (char) 0,
  471.             sizeof(map_info->t_start));
  472.     (void) memset((genericptr_t) map_info->t_stop, (char) COLNO-1,
  473.             sizeof(map_info->t_stop));
  474. #ifdef TEXTCOLOR
  475.     (void) memset((genericptr_t) map_info->colors, NO_COLOR,
  476.             sizeof(map_info->colors));
  477. #endif
  478.     display_map_window(wp);
  479. }
  480.  
  481. /*
  482.  * Retreive the font associated with the map window and save attributes
  483.  * that are used when updating it.
  484.  */
  485. static void
  486. get_char_info(wp)
  487.     struct xwindow *wp;
  488. {
  489.     XFontStruct *fs;
  490.  
  491.     fs = WindowFontStruct(wp->w);
  492.     wp->map_information->char_width    = fs->max_bounds.width;
  493.     wp->map_information->char_height   = fs->max_bounds.ascent +
  494.                         fs->max_bounds.descent;
  495.     wp->map_information->char_ascent   = fs->max_bounds.ascent;
  496.     wp->map_information->char_lbearing = -fs->min_bounds.lbearing;
  497.  
  498. #ifdef VERBOSE
  499.     printf("Font information:\n");
  500.     printf("fid = %d, direction = %d\n", fs->fid, fs->direction);
  501.     printf("first = %d, last = %d\n",
  502.             fs->min_char_or_byte2, fs->max_char_or_byte2);
  503.     printf("all chars exist? %s\n", fs->all_chars_exist?"yes":"no");
  504.     printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
  505.         fs->min_bounds.lbearing, fs->min_bounds.rbearing,
  506.         fs->min_bounds.width, fs->min_bounds.ascent,
  507.         fs->min_bounds.descent, fs->min_bounds.attributes);
  508.     printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n",
  509.         fs->max_bounds.lbearing, fs->max_bounds.rbearing,
  510.         fs->max_bounds.width, fs->max_bounds.ascent,
  511.         fs->max_bounds.descent, fs->max_bounds.attributes);
  512.     printf("per_char = 0x%x\n", fs->per_char);
  513.     printf("Text: (max) width = %d, height = %d\n",
  514.         wp->map_information->char_width, wp->map_information->char_height);
  515. #endif
  516.  
  517.     if (fs->min_bounds.width != fs->max_bounds.width)
  518.     X11_raw_print("Warning:  map font is not monospaced!");
  519. }
  520.  
  521. /*
  522.  * keyhit buffer
  523.  */
  524. #define INBUF_SIZE 64
  525. int inbuf[INBUF_SIZE];
  526. int incount = 0;
  527. int inptr = 0;    /* points to valid data */
  528.  
  529.  
  530. /*
  531.  * Keyboard and button event handler for map window.
  532.  */
  533. void
  534. map_input(w, event, params, num_params)
  535.     Widget   w;
  536.     XEvent   *event;
  537.     String   *params;
  538.     Cardinal *num_params;
  539. {
  540.     XKeyEvent *key;
  541.     XButtonEvent *button;
  542.     boolean meta = FALSE;
  543.     int i, nbytes;
  544.     Cardinal in_nparams = (num_params ? *num_params : 0);
  545.     char c;
  546.     char keystring[MAX_KEY_STRING];
  547.  
  548.     switch (event->type) {
  549.     case ButtonPress:
  550.         button = (XButtonEvent *) event;
  551. #ifdef VERBOSE_INPUT
  552.         printf("button press\n");
  553. #endif
  554.         if (in_nparams > 0 &&
  555.         (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
  556.         Strcpy(keystring, params[0]);
  557.         key = (XKeyEvent *) event; /* just in case */
  558.         goto key_events;
  559.         }
  560.         set_button_values(w, button->x, button->y, button->button);
  561.         break;
  562.     case KeyPress:
  563. #ifdef VERBOSE_INPUT
  564.         printf("key: ");
  565. #endif
  566.         if(appResources.slow && input_func) {
  567.         (*input_func)(w, event, params, num_params);
  568.         break;
  569.         }
  570.  
  571.         /*
  572.          * Don't use key_event_to_char() because we want to be able
  573.          * to allow keys mapped to multiple characters.
  574.          */
  575.         key = (XKeyEvent *) event;
  576.         if (in_nparams > 0 &&
  577.         (nbytes = strlen(params[0])) < MAX_KEY_STRING) {
  578.         Strcpy(keystring, params[0]);
  579.         } else {
  580.         /*
  581.          * Assume that mod1 is really the meta key.
  582.          */
  583.         meta = !!(key->state & Mod1Mask);
  584.         nbytes =
  585.             XLookupString(key, keystring, MAX_KEY_STRING,
  586.                   (KeySym *)0, (XComposeStatus *)0);
  587.         }
  588.     key_events:
  589.         /* Modifier keys return a zero length string when pressed. */
  590.         if (nbytes) {
  591. #ifdef VERBOSE_INPUT
  592.         printf("\"");
  593. #endif
  594.         for (i = 0; i < nbytes; i++) {
  595.             c = keystring[i];
  596.  
  597.             if (incount < INBUF_SIZE) {
  598.             inbuf[(inptr+incount)%INBUF_SIZE] =
  599.                 ((int) c) + (meta ? 0x80 : 0);
  600.             incount++;
  601.             } else {
  602.             X11_nhbell();
  603.             }
  604. #ifdef VERBOSE_INPUT
  605.             if (meta)            /* meta will print as M<c> */
  606.             (void) putchar('M');
  607.             if (c < ' ') {        /* ctrl will print as ^<c> */
  608.             (void) putchar('^');
  609.             c += '@';
  610.             }
  611.             (void) putchar(c);
  612. #endif
  613.         }
  614. #ifdef VERBOSE_INPUT
  615.         printf("\" [%d bytes]\n", nbytes);
  616. #endif
  617.         }
  618.         break;
  619.  
  620.     default:
  621.         impossible("unexpected X event, type = %d\n", (int) event->type);
  622.         break;
  623.     }
  624. }
  625.  
  626. static void
  627. set_button_values(w, x, y, button)
  628.     Widget w;
  629.     int x;
  630.     int y;
  631.     unsigned int button;
  632. {
  633.     struct xwindow *wp;
  634.     struct map_info_t *map_info;
  635.  
  636.     wp = find_widget(w);
  637.     map_info = wp->map_information;
  638.  
  639.     click_x = x / map_info->char_width;
  640.     click_y = y / map_info->char_height;
  641.  
  642.     /* The values can be out of range if the map window has been resized */
  643.     /* to be larger than the max size.                     */
  644.     if (click_x >= COLNO) click_x = COLNO-1;
  645.     if (click_y >= ROWNO) click_x = ROWNO-1;
  646.  
  647.     /* Map all buttons but the first to the second click */
  648.     click_button = (button == Button1) ? CLICK_1 : CLICK_2;
  649. }
  650.  
  651. /*
  652.  * Map window expose callback.
  653.  */
  654. /*ARGSUSED*/
  655. static void
  656. map_exposed(w, client_data, widget_data)
  657.     Widget w;
  658.     XtPointer client_data;    /* unused */
  659.     XtPointer widget_data;    /* expose event from Window widget */
  660. {
  661.     int x, y;
  662.     struct xwindow *wp;
  663.     struct map_info_t *map_info;
  664.     unsigned width, height;
  665.     int start_row, stop_row, start_col, stop_col;
  666.     XExposeEvent *event = (XExposeEvent *) widget_data;
  667.  
  668.     if (!XtIsRealized(w) || event->count > 0) return;
  669.  
  670.     wp = find_widget(w);
  671.     map_info = wp->map_information;
  672.     /*
  673.      * The map is sent an expose event when the viewport resizes.  Make sure
  674.      * that the cursor is still in the viewport after the resize.
  675.      */
  676.     map_check_size_change(wp);
  677.  
  678.     if (event) {        /* called from button-event */
  679.     x      = event->x;
  680.     y      = event->y;
  681.     width  = event->width;
  682.     height = event->height;
  683.     } else {
  684.     x     = 0;
  685.     y     = 0;
  686.     width = wp->pixel_width;
  687.     height= wp->pixel_height;
  688.     }
  689.     /*
  690.      * Convert pixels into INCLUSIVE text rows and columns.
  691.      */
  692.     start_row = y / map_info->char_height;
  693.     stop_row = start_row + (height / map_info->char_height) +
  694.             (((height % map_info->char_height) == 0) ? 0 : 1) - 1;
  695.  
  696.     start_col = x / map_info->char_width;
  697.     stop_col = start_col + (width / map_info->char_width) +
  698.             (((width % map_info->char_width) == 0) ? 0 : 1) - 1;
  699.  
  700. #ifdef VERBOSE
  701.     printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n",
  702.                             x, y, width, height);
  703. #endif
  704.  
  705.     /* Out of range values are possible if the map window is resized to be */
  706.     /* bigger than the largest expected value.                   */
  707.     if (stop_row >= ROWNO) stop_row = ROWNO-1;
  708.     if (stop_col >= COLNO) stop_col = COLNO-1;
  709.  
  710.     map_update(wp, start_row, stop_row, start_col, stop_col, FALSE);
  711.     display_cursor(wp);        /* make sure cursor shows up */
  712. }
  713.  
  714. /*
  715.  * Do the actual work of the putting characters onto our X window.  This
  716.  * is called from the expose event routine, the display window (flush)
  717.  * routine, and the display cursor routine.  The later is a kludge that
  718.  * involves the inverted parameter of this function.  A better solution
  719.  * would be to double the color count, with any color above MAXCOLORS
  720.  * being inverted.
  721.  *
  722.  * This works for rectangular regions (this includes one line rectangles).
  723.  * The start and stop columns are *inclusive*.
  724.  */
  725. static void
  726. map_update(wp, start_row, stop_row, start_col, stop_col, inverted)
  727.     struct xwindow *wp;
  728.     int start_row, stop_row, start_col, stop_col;
  729.     boolean inverted;
  730. {
  731.     int win_start_row, win_start_col;
  732.     struct map_info_t *map_info = wp->map_information;
  733.     int row;
  734.     register int count;
  735.  
  736.     if (start_row < 0 || stop_row >= ROWNO) {
  737.     impossible("map_update:  bad row range %d-%d\n", start_row, stop_row);
  738.     return;
  739.     }
  740.     if (start_col < 0 || stop_col >=COLNO) {
  741.     impossible("map_update:  bad col range %d-%d\n", start_col, stop_col);
  742.     return;
  743.     }
  744.  
  745. #ifdef VERBOSE_UPDATE
  746.     printf("update: [0x%x] %d %d %d %d\n", 
  747.         (int) wp->w, start_row, stop_row, start_col, stop_col);
  748. #endif
  749.     win_start_row = start_row;
  750.     win_start_col = start_col;
  751.  
  752. #ifdef TEXTCOLOR
  753.     if (flags.use_color) {
  754.     register char *c_ptr;
  755.     char *t_ptr;
  756.     int cur_col, color, win_ystart;
  757.  
  758.     for (row = start_row; row <= stop_row; row++) {
  759.         win_ystart = map_info->char_ascent +
  760.                     (row * map_info->char_height);
  761.  
  762.         t_ptr = (char *) &(map_info->text[row][start_col]);
  763.         c_ptr = (char *) &(map_info->colors[row][start_col]);
  764.         cur_col = start_col;
  765.         while (cur_col <= stop_col) {
  766.         color = *c_ptr++;
  767.         count = 1;
  768.         while ((cur_col + count) <= stop_col && *c_ptr == color) {
  769.             count++;
  770.             c_ptr++;
  771.         }
  772.  
  773.         XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
  774.             inverted ? map_info->inv_color_gcs[color] :
  775.                    map_info->color_gcs[color],
  776.             map_info->char_lbearing + (map_info->char_width * cur_col),
  777.             win_ystart,
  778.             t_ptr, count);
  779.  
  780.         /* move text pointer and column count */
  781.         t_ptr += count;
  782.         cur_col += count;
  783.         } /* col loop */
  784.     } /* row loop */
  785.     } else
  786. #endif /* TEXTCOLOR */
  787.     {
  788.     int win_row, win_xstart;
  789.  
  790.     /* We always start at the same x window position and have    */
  791.     /* the same character count.                    */
  792.     win_xstart = map_info->char_lbearing +
  793.                     (win_start_col * map_info->char_width);
  794.     count = stop_col - start_col + 1;
  795.  
  796.     for (row = start_row, win_row = win_start_row;
  797.                     row <= stop_row; row++, win_row++) {
  798.  
  799.         XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w),
  800.         inverted ? map_info->inv_copy_gc : map_info->copy_gc,
  801.         win_xstart,
  802.         map_info->char_ascent + (win_row * map_info->char_height),
  803.         (char *) &(map_info->text[row][start_col]), count);
  804.     }
  805.     }
  806. }
  807.  
  808. /* Adjust the number of rows and columns on the given map window */
  809. void
  810. set_map_size(wp, cols, rows)
  811.     struct xwindow *wp;
  812.     Dimension cols, rows;
  813. {
  814.     Arg args[4];
  815.     Cardinal num_args;
  816.  
  817.     wp->pixel_width  = wp->map_information->char_width  * cols;
  818.     wp->pixel_height = wp->map_information->char_height * rows;
  819.  
  820.     num_args = 0;
  821.     XtSetArg(args[num_args], XtNwidth, wp->pixel_width);   num_args++;
  822.     XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++;
  823.     XtSetValues(wp->w, args, num_args);
  824. }
  825.  
  826. /*
  827.  * The map window creation routine.
  828.  */
  829. void
  830. create_map_window(wp, create_popup, parent)
  831.     struct xwindow *wp;
  832.     boolean create_popup;    /* parent is a popup shell that we create */
  833.     Widget parent;
  834. {
  835.     struct map_info_t *map_info;    /* map info pointer */
  836.     Widget map, viewport;
  837.     Arg args[10];
  838.     Cardinal num_args;
  839.     Dimension rows, columns;
  840.  
  841.     wp->type = NHW_MAP;
  842.  
  843.     map_info = wp->map_information =
  844.             (struct map_info_t *) alloc(sizeof(struct map_info_t));
  845.  
  846.     map_info->viewport_width = map_info->viewport_height = 0;
  847.     (void) memset((genericptr_t) map_info->text, ' ', sizeof(map_info->text));
  848.     (void) memset((genericptr_t) map_info->t_start, (char) COLNO,
  849.             sizeof(map_info->t_start));
  850.     (void) memset((genericptr_t) map_info->t_stop, (char) 0,
  851.             sizeof(map_info->t_stop));
  852. #ifdef TEXTCOLOR
  853.     (void) memset((genericptr_t) map_info->colors, NO_COLOR,
  854.             sizeof(map_info->colors));
  855. #endif
  856.  
  857.     if (create_popup) {
  858.     /*
  859.      * Create a popup that accepts key and button events.
  860.      */
  861.     num_args = 0;
  862.     XtSetArg(args[num_args], XtNinput, False);            num_args++;
  863.  
  864.     wp->popup = parent = XtCreatePopupShell("nethack",
  865.                     topLevelShellWidgetClass,
  866.                        toplevel, args, num_args);
  867.     /*
  868.      * If we're here, then this is an auxiliary map window.  If we're
  869.      * cancelled via a delete window message, we should just pop down.
  870.      */
  871.     }
  872.  
  873.     num_args = 0;
  874.     XtSetArg(args[num_args], XtNallowHoriz, True);    num_args++;
  875.     XtSetArg(args[num_args], XtNallowVert,  True);    num_args++;
  876.     /* XtSetArg(args[num_args], XtNforceBars,  True);    num_args++; */
  877.     XtSetArg(args[num_args], XtNuseBottom,  True);    num_args++;
  878.     viewport = XtCreateManagedWidget(
  879.             "map_viewport",        /* name */
  880.             viewportWidgetClass,    /* widget class from Window.h */
  881.             parent,            /* parent widget */
  882.             args,            /* set some values */
  883.             num_args);        /* number of values to set */
  884.  
  885.     /*
  886.      * Create a map window.  We need to set the width and height to some
  887.      * value when we create it.  We will change it to the value we want
  888.      * later
  889.      */
  890.     num_args = 0;
  891.     XtSetArg(args[num_args], XtNwidth,  100); num_args++;
  892.     XtSetArg(args[num_args], XtNheight, 100); num_args++;
  893.  
  894.     wp->w = map = XtCreateManagedWidget(
  895.         "map",            /* name */
  896.         windowWidgetClass,    /* widget class from Window.h */
  897.         viewport,        /* parent widget */
  898.         args,            /* set some values */
  899.         num_args);        /* number of values to set */
  900.  
  901.     XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0);
  902.  
  903.     get_char_info(wp);
  904.     get_gc(wp, WindowFont(map));
  905.  
  906.     /*
  907.      * Initially, set the map widget to be the size specified by the
  908.      * widget rows and columns resources.  We need to do this to
  909.      * correctly set the viewport window size.  After the viewport is
  910.      * realized, then the map can resize to its normal size.
  911.      */
  912.     num_args = 0;
  913.     XtSetArg(args[num_args], XtNrows,    &rows);    num_args++;
  914.     XtSetArg(args[num_args], XtNcolumns, &columns);    num_args++;
  915.     XtGetValues(wp->w, args, num_args);
  916.  
  917.     /* Don't bother with windows larger than ROWNOxCOLNO. */
  918.     if (columns > COLNO) columns = COLNO;
  919.     if (rows    > ROWNO) rows = ROWNO;
  920.  
  921.     set_map_size(wp, columns, rows);
  922.  
  923.     /*
  924.      * If we have created our own popup, then realize it so that the
  925.      * viewport is also realized.  Then resize the map window.
  926.      */
  927.     if (create_popup) {
  928.     XtRealizeWidget(wp->popup);
  929.     XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup),
  930.             &wm_delete_window, 1);
  931.     set_map_size(wp, COLNO, ROWNO);
  932.     }
  933. }
  934.  
  935. /*
  936.  * Destroy this map window.
  937.  */
  938. void
  939. destroy_map_window(wp)
  940.     struct xwindow *wp;
  941. {
  942.     struct map_info_t *map_info = wp->map_information;
  943. #ifdef TEXTCOLOR
  944.     int i;
  945. #endif
  946.  
  947.     if (wp->popup) {
  948.     nh_XtPopdown(wp->popup);
  949.  
  950.     /* Free allocated GCs. */
  951. #ifdef TEXTCOLOR
  952.     for (i = 0; i < MAXCOLORS; i++) {
  953.         XtReleaseGC(wp->w, map_info->color_gcs[i]);
  954.         XtReleaseGC(wp->w, map_info->inv_color_gcs[i]);
  955.     }
  956. #else
  957.     XtReleaseGC(wp->w, map_info->copy_gc);
  958.     XtReleaseGC(wp->w, map_info->inv_copy_gc);
  959. #endif
  960.  
  961.     /* Free malloc'ed space. */
  962.     free((char *) map_info);
  963.  
  964.     /* Destroy map widget. */
  965.     XtDestroyWidget(wp->popup);
  966.     }
  967.  
  968.     wp->type = NHW_NONE;    /* allow re-use */
  969. }
  970.  
  971.  
  972.  
  973. boolean exit_x_event;    /* exit condition for the event loop */
  974. /*******
  975. pkey(k)
  976.     int k;
  977. {
  978.     printf("key = '%s%c'\n", (k<32) ? "^":"", (k<32) ? '@'+k : k);
  979. }
  980. ******/
  981.  
  982. /*
  983.  * Main X event loop.  Here we accept and dispatch X events.  We only exit
  984.  * under certain circumstances.
  985.  */
  986. int
  987. x_event(exit_condition)
  988.     int exit_condition;
  989. {
  990.     XEvent  event;
  991.     int     retval;
  992.     boolean keep_going = TRUE;
  993.  
  994. #ifdef GCC_WARN
  995.     retval = 0;
  996. #endif
  997.  
  998.     click_button = NO_CLICK;    /* reset click exit condition */
  999.     exit_x_event = FALSE;    /* reset callback exit condition */
  1000.  
  1001.     /*
  1002.      * Loop until we get a sent event, callback exit, or are accepting key
  1003.      * press and button press events and we receive one.
  1004.      */
  1005.     if((exit_condition == EXIT_ON_KEY_PRESS ||
  1006.     exit_condition == EXIT_ON_KEY_OR_BUTTON_PRESS) && incount)
  1007.     goto try_test;
  1008.  
  1009.     do {
  1010.     XtAppNextEvent(app_context, &event);
  1011.     XtDispatchEvent(&event);
  1012.  
  1013.     /* See if we can exit. */
  1014.     try_test:
  1015.     switch (exit_condition) {
  1016.         case EXIT_ON_SENT_EVENT: {
  1017.         XAnyEvent *any = (XAnyEvent *) &event;
  1018.         if (any->send_event) {
  1019.             retval = 0;
  1020.             keep_going = FALSE;
  1021.         }
  1022.         break;
  1023.         }
  1024.         case EXIT_ON_EXIT:
  1025.         if (exit_x_event) {
  1026.             incount = 0;
  1027.             retval = 0;
  1028.             keep_going = FALSE;
  1029.         }
  1030.         break;
  1031.         case EXIT_ON_KEY_PRESS:
  1032.         if (incount != 0) {
  1033.             /* get first pressed key */
  1034.             --incount;
  1035.             retval = inbuf[inptr];
  1036.             inptr = (inptr+1) % INBUF_SIZE;
  1037.             /* pkey(retval); */
  1038.             keep_going = FALSE;
  1039.         }
  1040.         break;
  1041.         case EXIT_ON_KEY_OR_BUTTON_PRESS:
  1042.         if (incount != 0 || click_button != NO_CLICK) {
  1043.             if (click_button != NO_CLICK) {    /* button press */
  1044.             /* click values are already set */
  1045.             retval = 0;
  1046.             } else {                /* key press */
  1047.             /* get first pressed key */
  1048.             --incount;
  1049.             retval = inbuf[inptr];
  1050.             inptr = (inptr+1) % INBUF_SIZE;
  1051.             /* pkey(retval); */
  1052.             }
  1053.             keep_going = FALSE;
  1054.         }
  1055.         break;
  1056.         default:
  1057.         panic("x_event: unknown exit condition %d\n", exit_condition);
  1058.         break;
  1059.     }
  1060.     } while (keep_going);
  1061.  
  1062.     return retval;
  1063. }
  1064.  
  1065. /*winmap.c*/
  1066.